package jfuzzyprincepless.zarchive.negotiation.protocols.propositionnetwork;

import java.util.List;

import jfuzzyprincepless.agents.INegotiatingAgent;
import jfuzzyprincepless.zarchive.algorithm.structure.forcnstr.*;
import jfuzzyprincepless.zarchive.negotiation.IAgentsExporter;
import jfuzzyprincepless.negotiation.IExecutionContext;
import jfuzzyprincepless.negotiation.INegotiationContext;
import jfuzzyprincepless.negotiation.impl.BaseNegotiation;

public class ExecuteForNegotiation<E>
	extends BaseNegotiation
	implements IExecuteForNegotiation<E>, IAgentsExporter
{
	private IForConstruction<E> forLoop;

	private ForLoopExecutor<E> forLoopExecutor;
	private DefaultForLoopRunnable negotiationRunnable;
	private DefaultForLoopRunnable executionRunnable;

	public ExecuteForNegotiation(
		INegotiationFor<E> forLoop,
		DefaultForLoopRunnable negotiationRunnable,
		DefaultForLoopRunnable executionRunnable
	) {
		this.forLoop = forLoop;
		this.negotiationRunnable = negotiationRunnable;
		this.executionRunnable = executionRunnable;
		forLoopExecutor = new ForLoopExecutor<E>(
			forLoop.getIterable()
		);
	}

	/**
	 * uses
	 * {@link ExecuteForNegotiation#ExecuteForNegotiation(INegotiationFor, DefaultForLoopRunnable, DefaultForLoopRunnable)}
	 * with arg1 = DefaultForLoopRunnable.NOP
	 * because both negotiation and execution stages
	 * are implemented in {@link ExecuteForNegotiation#execute(IExecutionContext)}
	 */
	public ExecuteForNegotiation(
		INegotiationFor<E> forLoop
	) {
		this(
			forLoop,
			DefaultForLoopRunnable.NOP,
			new DefaultForLoopRunnable(
				new DefaultNegotiation__Q(forLoop, forLoop),
				null,
				null
			)
		);
	}

	@Override
	public void negotiate(INegotiationContext context) {
		context.registerService(this);
		runFor(context, negotiationRunnable);
	}

	@Override
	public void execute(final IExecutionContext econtext) {
		// FIXM E: same ugly as with tmpContext
		INegotiationContext context =
			(INegotiationContext) econtext;
		runFor(context, executionRunnable);
	}

	private void runFor(
		INegotiationContext context,
		DefaultForLoopRunnable runnable
	) {
		// archivetodo F IXME: same ugly as with tmpContext
		synchronized(runnable) {
			runnable.setNegotiationContext(context);
			runnable.setExecutionContext(context);
			forLoopExecutor.execute(runnable);
		}
	}

	@Override
	public E getCurrentElem() {
		return forLoopExecutor.getCurrentElem();
	}

	@Override
	public IForConstruction<E> getForConstruction() {
		return forLoop;
	}

	public static <E> ExecuteForNegotiation<E> newSeparateFor(
		INegotiationFor<E> forLoop
	) {
		DefaultForLoopRunnable negotiationRunnable =
			new DefaultForLoopRunnable(
				new DefaultNegotiation__Q(forLoop, forLoop),
				(INegotiationContext)null
			);
		DefaultForLoopRunnable executionRunnable =
			new DefaultForLoopRunnable(
				new DefaultNegotiation__Q(forLoop, forLoop),
				(IExecutionContext)null
			);
		return new ExecuteForNegotiation<E>(
			forLoop,
			negotiationRunnable,
			executionRunnable
		);
	}

	@Override
	public List<INegotiatingAgent> getAgents() {
		return ((IAgentsExporter)negotiationRunnable
			.getSubnegotiation()).getAgents();
	}
}
